﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using XDL.Framework.Particles;
using XDL.Framework;
using JumpNFight.Simulation;
using XDL.Framework.Weapons;

namespace JumpNFight.Weapons
{
    /// <summary>
    /// Base class to support balistic weapons (e.g. not using the particle framework)
    /// </summary>
    abstract class BalisticWeaponSystemBase :
        IWeaponSystem,
        IWeapon
    {
        AudioManager m_audio;
        List<BalisticWeaponBase> m_weapons = new List<BalisticWeaponBase>(8);

        protected readonly static Random Rnd = new Random();

        protected AudioManager Audio
        {
            get
            {
                return m_audio;
            }
        }

        protected World World
        {
            get;
            private set;
        }

        public List<BalisticWeaponBase> Entities
        {
            get
            {
                return m_weapons;
            }
        }

        public BalisticWeaponSystemBase(Game game) 
        { }

        protected abstract string WeaponName
        {
            get;
        }

        protected virtual bool ShakeWorld
        {
            get
            {
                return false;
            }
        }

        public virtual void Initialize()
        {
            Settings = GameServices.LoadContent<WeaponSettings>(WeaponName);
            m_audio = GameServices.GetService<AudioManager>();
            this.World = GameServices.GetService<World>();
        }

        public WeaponSettings Settings
        {
            get;
            private set;
        }

        /// <summary>
        /// Creates a new instance of the weapon "bullet"
        /// </summary>
        /// <param name="ownerID">Weapon owner</param>
        /// <param name="position">Firing position</param>
        /// <param name="direction">Firing direction</param>
        /// <returns>A new instance of the weapon</returns>
        protected abstract BalisticWeaponBase CreateWeapon(int ownerID, Vector3 position, Vector3 direction);

        public void Fire(int ownerID, Vector3 position, Vector3 direction)
        {
            //
            BalisticWeaponBase weapon = CreateWeapon(ownerID, position, direction);
            // register the object in the event system
            GameServices.EventDispatcher.RegisterClient(weapon);

            m_weapons.Add(weapon);
 
            // per-weapon sound
            m_audio.PlayCue(Settings.Name + "/Fire");
        }

        /// <summary>
        /// Virtual method to trigger specific action when the weapon is to be discarded (usually end of life)
        /// </summary>
        /// <param name="weapon">Weapon to discard</param>
        protected virtual void Kill(BalisticWeaponBase weapon)
        {
            weapon.Kill();
        }

        /// <summary>
        /// Virtual method to trigger specific action when the action hits something
        /// </summary>
        /// <param name="weapon"></param>
        protected virtual void Hit(BalisticWeaponBase weapon)
        {
            weapon.Kill();
        }

        public virtual void Update(GameTime gameTime)
        {
            //
            for (int i = m_weapons.Count - 1; i >= 0; i--)
            {
                BalisticWeaponBase weapon = m_weapons[i];

                if (weapon.HitWall)
                {
                    m_audio.PlayCue(Settings.Name + "/Ricochet");
                    weapon.HitWall = false;
                }

                weapon.Update(gameTime);

                // no more active?
                if (weapon.Discard)
                {
                    // boom!!
                    Kill(weapon);

                    if (ShakeWorld)
                        this.World.Shake();
                    //
                    m_weapons.RemoveAt(i);
                    continue;
                }                

                this.World.Adjust(weapon.Moveable, gameTime);

                // compute collision with bad guys
                if (weapon.IsActive && Intersect(weapon))
                {
                    // boom!!
                    Hit(weapon);

                    if (ShakeWorld)
                        this.World.Shake();

                    m_weapons.RemoveAt(i);
                    continue;
                }
            }
        }

        protected virtual bool Intersect(BalisticWeaponBase grenade)
        {
            BoundingSphere bs = new BoundingSphere(new Vector3(grenade.Moveable.X, grenade.Moveable.Y, 0), 4);
            foreach (BadGuy it in this.World.NPCs)
            {
                if (it.IsAlive && it.Moveable.Intersects(bs) )
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// Removes any pending active entities
        /// </summary>
        /// <remarks>
        /// Assumes the event dispatcher system is cleared afterward
        /// </remarks>
        public void Clear()
        {
            m_weapons.Clear();
        }
    }
}
